#include <stdio.h>
#include "gd32f30x.h"
#include "message.h"
#include <string.h>

#ifdef ENABLE_SPI_TEST
#include "spi.h"
#endif

#if SPI_MODE == SPI_MASTER_MODE_POLL
#define spi1_cs_high gpio_bit_set(GPIOB,GPIO_PIN_12)
#define spi1_cs_low  gpio_bit_reset(GPIOB,GPIO_PIN_12)

void spi1_config(void)
{
    spi_parameter_struct spi_init_struct;

    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_SPI1);
    rcu_periph_clock_enable(RCU_AF);

    /* SPI1 GPIO config:SCK/PB13, MISO/PB14, MOSI/PB15 */
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_15);
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    /* PB12 as NSS */
    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);

    /* SPI1 parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_16; //速率
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI1, &spi_init_struct);
    
    spi_enable(SPI1);
}

static void spi1_write_read_onebyte(uint8_t w_data,uint8_t *r_data)
{
    while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));
    spi_i2s_data_transmit(SPI1, w_data);
    while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE));
    *r_data = spi_i2s_data_receive(SPI1);
}

uint8_t spi1_rw_onebyte(uint8_t w_data)
{
    uint8_t value;
    while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));
    spi_i2s_data_transmit(SPI1, w_data);
    while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE));
    value = spi_i2s_data_receive(SPI1);
    return value;
}

void spi1_write_read_data(uint8_t *w_data,uint8_t *r_data,int len)
{
    spi1_cs_low;
    while (len)
    {
        spi1_write_read_onebyte(*w_data++,r_data++);
        len--;
    }
    spi1_cs_high;
}



void spi1_write_data(uint8_t *w_data,int len)
{
    spi1_cs_low;
    while (len)
    {
        while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));
        spi_i2s_data_transmit(SPI1, *w_data++);
        len--;
    }
    spi1_cs_high; 
}

void spi1_read_data(uint8_t *r_data,int len)
{
    spi1_cs_low;
    while (len)
    {
        while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));
        *r_data = spi_i2s_data_receive(SPI1);
        len--;
    }
    spi1_cs_high; 
}

#elif SPI_MODE == SPI_MASTER_MODE_DMA
#define spi1_cs_high gpio_bit_set(GPIOB,GPIO_PIN_12)
#define spi1_cs_low  gpio_bit_reset(GPIOB,GPIO_PIN_12)

static void spi1_dma_tx_config(uint8_t *p_data,uint8_t len)
{
    dma_parameter_struct dma_init_struct;
    /* initialize DMA channel4 */
    dma_deinit(DMA0, DMA_CH4);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = (uint32_t)p_data;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = len;
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI1);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_LOW;
    dma_init(DMA0, DMA_CH4, &dma_init_struct);

    dma_circulation_disable(DMA0, DMA_CH4);
    dma_memory_to_memory_disable(DMA0, DMA_CH4);
}

static void spi1_dma_rx_config(uint8_t *p_data,uint8_t len)
{
    dma_parameter_struct dma_init_struct;
    /* initialize DMA channel3 */
    dma_deinit(DMA0, DMA_CH3);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)p_data;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = len;
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI1);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_LOW;
    dma_init(DMA0, DMA_CH3, &dma_init_struct);

    dma_circulation_disable(DMA0, DMA_CH3);
    dma_memory_to_memory_disable(DMA0, DMA_CH3);


}

void spi1_dma_tx_data(uint8_t *p_data,uint8_t len)
{
    spi1_cs_low;
    spi1_dma_tx_config(p_data,len);
    /* DMA channel enable */
    dma_channel_enable(DMA0, DMA_CH4);
 
    /* SPI DMA enable */
    spi_dma_enable(SPI1, SPI_DMA_TRANSMIT);

    /* wait dma transmit complete */
    while(!dma_flag_get(DMA0,DMA_CH4, DMA_INTF_FTFIF)) {
    }

    spi1_cs_high;
}

void spi1_dma_rx_data(uint8_t *p_data,uint8_t len)
{
    spi1_cs_low;
    spi1_dma_rx_config(p_data,len);
    /* DMA channel enable */
    dma_channel_enable(DMA0, DMA_CH3);
    /* SPI DMA enable */
    spi_dma_enable(SPI1, SPI_DMA_RECEIVE);

    /* wait dma transmit complete */
    while(!dma_flag_get(DMA0,DMA_CH3, DMA_INTF_FTFIF)) {
    }

    spi1_cs_high;
}


void spi1_dma_init(void)
{
    spi_parameter_struct spi_init_struct;
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_SPI1);
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_DMA0);

    /* SPI1 GPIO config:SCK/PB13, MISO/PB14, MOSI/PB15 */
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_15);
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    /* PB12 as NSS */
    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);

    /* SPI1 parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_16; //速率
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI1, &spi_init_struct);

    
    spi_enable(SPI1);

}
#elif SPI_MODE == SPI_MASTER_SLAVE_MODE_POLL

void spi0_master_config(void)
{
    spi_parameter_struct spi_init_struct;

    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_SPI0);
    rcu_periph_clock_enable(RCU_AF);

    /* SPI0 GPIO config:SCK/PA5, MISO/PA6, MOSI/PA7 */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    /* PA4 as NSS */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);


    /* SPI parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_16; //速率
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi_init_struct);
    spi_enable(SPI0);
}

void spi1_slave_config(void)
{
    spi_parameter_struct spi_init_struct;

    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_SPI1);
    rcu_periph_clock_enable(RCU_AF);

    /* SPI1 GPIO config:SCK/PB13, MISO/PB14, MOSI/PB15 */
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_15);
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    /* PB12 as NSS */
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_12);

    /* SPI1 parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_SLAVE;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_HARD;
    spi_init_struct.prescale             = SPI_PSC_16; //速率
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI1, &spi_init_struct);

    //nvic_irq_enable(SPI1_IRQn,2,0);
    /* SPI int enable */
    // spi_i2s_interrupt_enable(SPI1, SPI_I2S_INT_TBE);
    //spi_i2s_interrupt_enable(SPI1, SPI_I2S_INT_RBNE);
    spi_enable(SPI1);
}

void spi_master_slave_fullduplex_poll(void)
{
    uint8_t master_tx_buf[16] = {0};
    uint8_t master_rx_buf[16] = {0};
    uint8_t slave_tx_buf[16] = {0};
    uint8_t slave_rx_buf[16] = {0};
    
    for(uint8_t i = 0; i < 16; ++i)
    {
        master_tx_buf[i] = 0x20 + i;
        slave_tx_buf[i] = 0x10 + i;
    }
    
    printf("Master have sended : ");
    for(uint8_t i = 0; i < 16; ++i)
    {
        printf("%x ", master_tx_buf[i]);
    }
    printf("\r\n");
    
    printf("Slave have sended : ");
    for(uint8_t i = 0; i < 16; ++i)
    {
        printf("%x ", slave_tx_buf[i]);
    }
    printf("\r\n");

    for(uint8_t i = 0; i < 16; ++i)
    {
        while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE));
        spi_i2s_data_transmit(SPI1, slave_tx_buf[i]);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));
        spi_i2s_data_transmit(SPI0, master_tx_buf[i]);
        while(RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_RBNE));
        slave_rx_buf[i] = spi_i2s_data_receive(SPI1);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));
        master_rx_buf[i] = spi_i2s_data_receive(SPI0);
    }
    
    printf("Master received  : ");
    for(uint8_t i = 0; i < 16; ++i)
    {
        printf("%x ", master_rx_buf[i]);
    }
    printf("\r\n");
    
    printf("Slave received  : ");
    for(uint8_t i = 0; i < 16; ++i)
    {
        printf("%x ", slave_rx_buf[i]);
    }
    printf("\r\n");
}

#elif SPI_MODE == SPI_MASTER_SLAVE_MODE_INT

void spi0_master_config(void)
{
    spi_parameter_struct spi_init_struct;

    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_SPI0);
    rcu_periph_clock_enable(RCU_AF);

    /* SPI0 GPIO config:SCK/PA5, MISO/PA6, MOSI/PA7 */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    /* PA4 as NSS */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);


    /* SPI parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_16; //速率
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi_init_struct);
    
    spi_enable(SPI0);
}

void spi1_slave_config(void)
{
    spi_parameter_struct spi_init_struct;

    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_SPI1);
    rcu_periph_clock_enable(RCU_AF);

    /* SPI1 GPIO config:SCK/PB13, MISO/PB14, MOSI/PB15 */
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_15);
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    /* PB12 as NSS */
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_12);

    /* SPI1 parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_SLAVE;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.nss                  = SPI_NSS_HARD;
    spi_init_struct.prescale             = SPI_PSC_16; //速率
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI1, &spi_init_struct);

    nvic_irq_enable(SPI1_IRQn,2,0);
    /* SPI int enable */
    //spi_i2s_interrupt_enable(SPI1, SPI_I2S_INT_TBE);
    spi_i2s_interrupt_enable(SPI1, SPI_I2S_INT_RBNE);
    spi_enable(SPI1);
}

void spi_master_slave_fullduplex_poll(void)
{
    uint8_t master_tx_buf[16] = {0};
    uint8_t master_rx_buf[16] = {0};
    uint8_t slave_tx_buf[16] = {0};
    uint8_t slave_rx_buf[16] = {0};
    
    for(uint8_t i = 0; i < 16; ++i)
    {
        master_tx_buf[i] = 0x20 + i;
        slave_tx_buf[i] = 0x10 + i;
    }
    
    printf("Master have sended : ");
    for(uint8_t i = 0; i < 16; ++i)
    {
        printf("%x ", master_tx_buf[i]);
    }
    printf("\r\n");
    
    for(uint8_t i = 0; i < 16; ++i)
    {
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));
        spi_i2s_data_transmit(SPI0, master_tx_buf[i]);
        // while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));
        // master_rx_buf[i] = spi_i2s_data_receive(SPI0);
    }
    
    // printf("Master received  : ");
    // for(uint8_t i = 0; i < 16; ++i)
    // {
    //     printf("%x ", master_rx_buf[i]);
    // }
    // printf("\r\n");
    
}


#endif //#if SPI_MODE == SPI_MASTER_MODE_POLL


